package bpmjs;

typedef Vector3T = {x : Float, y : Float, z : Float, tx : Float, ty : Float, tz : Float};

class Matrix4
{
	public var n11 : Float;
	public var n12 : Float;
	public var n13 : Float;
	public var n14 : Float;

	public var n21 : Float;
	public var n22 : Float;
	public var n23 : Float;
	public var n24 : Float;

	public var n31 : Float;
	public var n32 : Float;
	public var n33 : Float;
	public var n34 : Float;

	public var n41 : Float;
	public var n42 : Float;
	public var n43 : Float;
	public var n44 : Float;
	
	public static function createEulerRotation(ax : Float, ay : Float, az : Float) : Matrix4
	{
		var m = new Matrix4();
		m.identity();

		var a:Float = Math.cos(ax);
		var b:Float = Math.sin(ax);
		var c:Float = Math.cos(ay);
		var d:Float = Math.sin(ay);
		var e:Float = Math.cos(az);
		var f:Float = Math.sin(az);
		
		var ad:Float = a * d;
		var bd:Float = b * d;

		m.n11 =  c * e;
		m.n12 =  c * f;
		m.n13 = - d;
		m.n21 =  bd * e - a * f;
		m.n22 =  bd * f + a * e;
		m.n23 =  b * c;
		m.n31 =  ad * e + b * f;
		m.n32 =  ad * f - b * e;
		m.n33 =  a * c;

		return m;
	}
		
	public static function createTranslation(x:Float, y:Float, z:Float) : Matrix4
	{
		var m = new Matrix4();
		m.identity();
		
		m.n14 = x;
		m.n24 = y;
		m.n34 = z;
		
		return m;
	}
		
	public static function createScale(x:Float, y:Float, z:Float) : Matrix4
	{
		var m = new Matrix4();
		m.identity();
		
		m.n11 = x;
		m.n22 = y;
		m.n33 = z;
		
		return m;
	}
		
	public function new()
	{
	}
	
	public function identity():Void
	{
		n11 = 1; n12 = 0; n13 = 0; n14 = 0;
		n21 = 0; n22 = 1; n23 = 0; n24 = 0;
		n31 = 0; n32 = 0; n33 = 1; n34 = 0;
		n41 = 0; n42 = 0; n43 = 0; n44 = 1;
	}
	
	public inline function transform(v : Vector3T) : Void
	{
		var x : Float = v.x;
		var y : Float = v.y;
		var z : Float = v.z;
		v.tx = (x * n11 + y * n12 + z * n13 + n14);
		v.ty = (x * n21 + y * n22 + z * n23 + n24);
		v.tz = (x * n31 + y * n32 + z * n33 + n34);
	}
	
	public function appendRotation(ax : Float, ay : Float, az : Float) : Void
	{
		append(createEulerRotation(ax, ay, az));
	}
	
	public function appendTranslation(x : Float, y : Float, z : Float) : Void
	{
		append(createTranslation(x, y, z));
	}
	
	public function appendScale(x : Float, y : Float, z : Float) : Void
	{
		append(createScale(x, y, z));
	}
	
	public function append(m2:Matrix4) : Void
	{
		var m111:Float = n11, m121:Float = n21, m131:Float = n31, m141:Float = n41,
			m112:Float = n12, m122:Float = n22, m132:Float = n32, m142:Float = n42,
			m113:Float = n13, m123:Float = n23, m133:Float = n33, m143:Float = n43,
			m114:Float = n14, m124:Float = n24, m134:Float = n34, m144:Float = n44,
			m211:Float = m2.n11, m221:Float = m2.n21, m231:Float = m2.n31, m241:Float = m2.n41,
			m212:Float = m2.n12, m222:Float = m2.n22, m232:Float = m2.n32, m242:Float = m2.n42,
			m213:Float = m2.n13, m223:Float = m2.n23, m233:Float = m2.n33, m243:Float = m2.n43,
			m214:Float = m2.n14, m224:Float = m2.n24, m234:Float = m2.n34, m244:Float = m2.n44;

		n11 = m111 * m211 + m112 * m221 + m113 * m231 + m114 * m241;
		n12 = m111 * m212 + m112 * m222 + m113 * m232 + m114 * m242;
		n13 = m111 * m213 + m112 * m223 + m113 * m233 + m114 * m243;
		n14 = m111 * m214 + m112 * m224 + m113 * m234 + m114 * m244;

		n21 = m121 * m211 + m122 * m221 + m123 * m231 + m124 * m241;
		n22 = m121 * m212 + m122 * m222 + m123 * m232 + m124 * m242;
		n23 = m121 * m213 + m122 * m223 + m123 * m233 + m124 * m243;
		n24 = m121 * m214 + m122 * m224 + m123 * m234 + m124 * m244;

		n31 = m131 * m211 + m132 * m221 + m133 * m231 + m134 * m241;
		n32 = m131 * m212 + m132 * m222 + m133 * m232 + m134 * m242;
		n33 = m131 * m213 + m132 * m223 + m133 * m233 + m134 * m243;
		n34 = m131 * m214 + m132 * m224 + m133 * m234 + m134 * m244;

		n41 = m141 * m211 + m142 * m221 + m143 * m231 + m144 * m241;
		n42 = m141 * m212 + m142 * m222 + m143 * m232 + m144 * m242;
		n43 = m141 * m213 + m142 * m223 + m143 * m233 + m144 * m243;
		n44 = m141 * m214 + m142 * m224 + m143 * m234 + m144 * m244;
	}
	
}
